/**
 * 
 */
package com.gr.staffpm.pages.schedule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.apache.wicket.model.Model;
import org.joda.time.DateTime;

import com.gr.staffpm.gof.observer.Subscribable;
import com.gr.staffpm.gof.observer.Subscriber;
import com.gr.staffpm.model.StringModel;
import com.gr.staffpm.pages.behaviour.ExtCalendarNavBehaviour;
import com.gr.staffpm.pages.schedule.model.MonthChoiceLink;
import com.gr.staffpm.pages.schedule.model.MonthRow;
import com.gr.staffpm.pages.schedule.model.YearChoiceLink;

/**
 * @author Graham Rhodes 17 Mar 2011 19:09:57
 */
public class ExtCalendarNav extends Panel implements Subscribable, Subscriber {

    private static final long serialVersionUID = 1L;
    private final AjaxLink<Void> prevMonthLink;
    private final AjaxButton monthChoice;
    private final AjaxLink<Void> nextMonthLink;
    private final List<MonthRow> monthRows = new ArrayList<MonthRow>();
    private final DateTime today = new DateTime();
    private DateTime currentDate, newYear = new DateTime(), newMonth = new DateTime();
    private final WebMarkupContainer monthYearChoice = new WebMarkupContainer("monthYearChoice");
    private final WebMarkupContainer datePicker = new WebMarkupContainer("datePicker");
    private final List<String> yearPickerLinks = Arrays.asList("y1Link", "y2Link", "y3Link", "y4Link", "y5Link", "y6Link", "y7Link", "y8Link", "y9Link", "y10Link");
    private final List<String> yearPickerLabels = Arrays.asList("y1Label", "y2Label", "y3Label", "y4Label", "y5Label", "y6Label", "y7Label", "y8Label", "y9Label", "y10Label");
    private final List<String> monthPickerLinks = Arrays.asList("janLink", "febLink", "marLink", "aprLink", "mayLink", "junLink", "julLink", "augLink", "sepLink", "octLink", "novLink",
            "decLink");
    private final List<Label> yearChoiceLabels = new ArrayList<Label>();
    private final List<AjaxLink<DateTime>> yearChoiceLinks = new ArrayList<AjaxLink<DateTime>>();
    private final List<Subscriber> subscribers = new ArrayList<Subscriber>();
    private final Label monthLabel;

    public ExtCalendarNav(String id) {
        super(id);

        datePicker.setOutputMarkupId(true);

        currentDate = new DateTime().withDayOfMonth(today.dayOfMonth().getMinimumValue());
        if (currentDate.getDayOfWeek() != 7)
            currentDate = currentDate.minusDays(currentDate.getDayOfWeek());

        for (int i = 0; i < 6; i++) {
            final DateTime[] days = new DateTime[7];
            for (int j = 0; j < 7; j++) {
                days[j] = currentDate;
                currentDate = currentDate.plusDays(1);
            }
            monthRows.add(new MonthRow(days));
        }
        currentDate = new DateTime().withDayOfMonth(today.dayOfMonth().getMinimumValue());

        prevMonthLink = new AjaxLink<Void>("prevMonthLink") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                prevMonthClicked(target);
            }

        };
        datePicker.add(prevMonthLink);

        nextMonthLink = new AjaxLink<Void>("nextMonthLink") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                nextMonthClicked(target);
            }

        };
        datePicker.add(nextMonthLink);

        Form<Void> todayButtonForm = new Form<Void>("todayButtonForm");
        todayButtonForm.add(new AjaxButton("todayButton", new Model<String>("Today")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                goToToday(target);
            }
        });
        datePicker.add(todayButtonForm);

        monthChoice = new AjaxButton("monthChoice", new Model<String>(currentDate.monthOfYear().getAsText())) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                displayMonthYearChoice(target);
            }
        };
        monthLabel = new Label("monthLabel", new StringModel(new DateTime().toString("MMMMM yyyy")));
        monthChoice.add(monthLabel);
        Form<Void> monthChoiceForm = new Form<Void>("monthChoiceForm");
        monthChoiceForm.add(monthChoice);
        datePicker.add(monthChoiceForm);

        datePicker.add(new DataView<MonthRow>("monthRows", new ListDataProvider<MonthRow>(monthRows)) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(Item<MonthRow> item) {
                MonthRow row = (MonthRow) item.getDefaultModelObject();
                RepeatingView monthDays = new RepeatingView("monthDays");
                for (int i = 1; i <= 7; i++) {
                    DayPanel dayPan = new DayPanel(String.valueOf(i), i, row, currentDate);
                    dayPan.addSubscriber(ExtCalendarNav.this);
                    monthDays.add(dayPan);
                }
                item.add(monthDays);
            }

        }.add(new ExtCalendarNavBehaviour(this)));

        for (int month = 0; month < 12; month++) {
            monthYearChoice.add(new MonthChoiceLink(monthPickerLinks.get(month), new DateTime().withMonthOfYear(month + 1), this));
        }

        for (int year = 0; year < 10; year++) {
            DateTime yearDateTime = new DateTime().withYear(currentDate.getYear() + (year - 4));
            Label yearLabel = new Label(yearPickerLabels.get(year), new StringModel(yearDateTime.toString("yyyy")));
            yearChoiceLabels.add(yearLabel);
            YearChoiceLink yearLink = new YearChoiceLink(yearPickerLinks.get(year), yearDateTime, this);
            yearChoiceLinks.add(yearLink);
            monthYearChoice.add(yearLink.add(yearLabel));
        }


        monthYearChoice.add(new AjaxLink<Void>("prevYLink") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                prevYearClicked(target);
            }

        });

        monthYearChoice.add(new AjaxLink<Void>("nextYLink") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                nextYearClicked(target);
            }

        });

        Form<Void> choiceForm = new Form<Void>("choiceForm");
        choiceForm.add(new AjaxButton("okButton") {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                submitMonthYearChoice(target);
            }

        });

        choiceForm.add(new AjaxButton("cancelButton") {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                hideMonthYearChoice(target);
            }

        });
        monthYearChoice.add(choiceForm);
        datePicker.add(monthYearChoice);

        add(datePicker);
    }

    public void submitMonthYearChoice() {
        currentDate = currentDate.withMonthOfYear(newMonth.getMonthOfYear()).withYear(newYear.getYear());
        monthYearChoice.add(new SimpleAttributeModifier("style", "width: 175px; height: 200px; visibility: visible; display: none; position: absolute; left: 0px; top: 0px; z-index: auto;"));
        updateCalendar();
    }

    public void submitMonthYearChoice(AjaxRequestTarget target) {
        currentDate = currentDate.withMonthOfYear(newMonth.getMonthOfYear()).withYear(newYear.getYear());
        monthYearChoice.add(new SimpleAttributeModifier("style", "width: 175px; height: 200px; visibility: visible; display: none; position: absolute; left: 0px; top: 0px; z-index: auto;"));
        updateCalendar(target);
    }

    protected void hideMonthYearChoice(AjaxRequestTarget target) {
        monthYearChoice.add(new SimpleAttributeModifier("style", "width: 175px; height: 200px; visibility: visible; display: none; position: absolute; left: 0px; top: 0px; z-index: auto;"));
        target.addComponent(datePicker);
    }

    protected void goToToday(AjaxRequestTarget target) {
        currentDate = new DateTime();
        notifySubscribers(Schedule.NAV_DAY_CLICKED, target);
        updateCalendar(target);
    }

    protected void nextYearClicked(AjaxRequestTarget target) {
        currentDate = currentDate.plusYears(10);
        updateCalendar(target);
    }

    protected void prevYearClicked(AjaxRequestTarget target) {
        currentDate = currentDate.minusYears(10);
        updateCalendar(target);
    }

    protected void nextMonthClicked(AjaxRequestTarget target) {
        currentDate = currentDate.plusMonths(1);
        updateCalendar(target);
    }

    protected void prevMonthClicked(AjaxRequestTarget target) {
        currentDate = currentDate.minusMonths(1);
        updateCalendar(target);
    }

    public void updateCalendar() {

        currentDate = currentDate.withDayOfMonth(currentDate.dayOfMonth().getMinimumValue());
        DateTime currDate = currentDate;
        if (currDate.getDayOfWeek() != 7) {
            currDate = currDate.minusDays(currDate.getDayOfWeek());
        }

        monthRows.removeAll(monthRows);
        for (int i = 0; i < 6; i++) {
            final DateTime[] days = new DateTime[7];
            for (int j = 0; j < 7; j++) {
                days[j] = currDate;
                currDate = currDate.plusDays(1);
            }
            monthRows.add(new MonthRow(days));
        }

        DateTime currYear = currentDate.withYear(currentDate.getYear() - 4);
        for (int i = 0; i < yearChoiceLabels.size(); i++) {
            yearChoiceLinks.get(i).setDefaultModelObject(currYear);
            yearChoiceLabels.get(i).setDefaultModelObject(currYear.toString("yyyy"));
            currYear = currYear.plusYears(1);
        }

        monthLabel.setDefaultModelObject(currentDate.toString("MMMMM yyyy"));
    }

    public void updateCalendar(AjaxRequestTarget target) {

        currentDate = currentDate.withDayOfMonth(currentDate.dayOfMonth().getMinimumValue());
        DateTime currDate = currentDate;
        if (currDate.getDayOfWeek() != 7) {
            currDate = currDate.minusDays(currDate.getDayOfWeek());
        }

        monthRows.removeAll(monthRows);
        for (int i = 0; i < 6; i++) {
            final DateTime[] days = new DateTime[7];
            for (int j = 0; j < 7; j++) {
                days[j] = currDate;
                currDate = currDate.plusDays(1);
            }
            monthRows.add(new MonthRow(days));
        }

        DateTime currYear = currentDate.withYear(currentDate.getYear() - 4);
        for (int i = 0; i < yearChoiceLabels.size(); i++) {
            yearChoiceLinks.get(i).setDefaultModelObject(currYear);
            yearChoiceLabels.get(i).setDefaultModelObject(currYear.toString("yyyy"));
            currYear = currYear.plusYears(1);
        }

        monthLabel.setDefaultModelObject(currentDate.toString("MMMMM yyyy"));

        target.addComponent(datePicker);
    }

    public void updateYear(DateTime year) {
        newYear = year;
    }

    public void updateMonth(DateTime month) {
        newMonth = month;
    }

    protected void displayMonthYearChoice(AjaxRequestTarget target) {
        monthYearChoice.add(new SimpleAttributeModifier("style", "width: 175px; height: 200px; visibility: visible; display: inline; position: absolute; left: 0px; top: 0px; z-index: auto;"));
        target.addComponent(datePicker);
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.Subscribable#addSubscriber(com.gr.staffpm.gof.observer.Subscriber)
     */
    @Override
    public void addSubscriber(Subscriber subscriber) {
        subscribers.add(subscriber);
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.Subscribable#notifySubscribers(java.lang.Object, org.apache.wicket.ajax.AjaxRequestTarget)
     */
    @Override
    public void notifySubscribers(Object object, AjaxRequestTarget target) {
        for (Subscriber subscriber : subscribers)
            subscriber.notifySubscriber(object, target);
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.Subscriber#subscribeTo(com.gr.staffpm.gof.observer.Subscribable)
     */
    @Override
    public void subscribeTo(Subscribable subscribable) {
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.Subscriber#notifySubscriber(java.lang.Object, org.apache.wicket.ajax.AjaxRequestTarget)
     */
    @Override
    public void notifySubscriber(Object object, AjaxRequestTarget target) {
        currentDate = (DateTime) object;
        notifySubscribers(Schedule.NAV_DAY_CLICKED, target);
    }

    public DateTime getCurrentDate() {
        return currentDate;
    }

}
